package com.mh.utils;

import cn.hutool.core.util.StrUtil;
import cn.hutool.http.ContentType;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.mh.constant.WxPayJsApiNotifyConstant;
import com.mh.constant.WxPayJsApiResponseConstant;
import com.mh.dao.PayInfoDao;
import com.mh.dto.bo.WxPayJsApiOrderBO;
import com.mh.pojo.PayInfo;
import com.mh.service.PayInfoService;
import com.wechat.pay.contrib.apache.httpclient.util.AesUtil;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.RequiredArgsConstructor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import java.io.BufferedReader;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.LinkedHashMap;
import java.util.Map;

/**
 * 微信回调相关工具函数
 */
@Component
@RequiredArgsConstructor
public class WxPayJsApiNotifyUtil {

    private static Logger logger = LoggerFactory.getLogger(WxPayJsApiNotifyUtil.class);
    /**
     * 商户API私钥
     **/
    @Value("${wxPay.jsApi.apiV3Key}")
    String apiV3Key;

    private final WxPayJsApiHttpUtil wxPayJsApiHttpUtil;

    private final PayInfoService payInfoService;

    /**
     * 微信支付回调状态处理逻辑
     */
    public String notifyV3(HttpServletRequest request, HttpServletResponse response) throws Exception {
        // 构建 - 微信支付回调通知body数据
        String body = getVerifyNotifyBody(request);
        // 需要通过证书序列号查找对应的证书，verifyNotify 中有验证证书的序列号
        // 解密，获取解密后的数据，内涵微信支付订单号
        String plainText = verifyNotify(body, apiV3Key);

        // 构建 - 微信支付回调通知map数据
        Map<String, String> map = new LinkedHashMap<>();
        if (StrUtil.isNotEmpty(plainText)) {
            response.setStatus(WxPayJsApiResponseConstant.RESPONSE_SUCCESS);
            map.put(WxPayJsApiResponseConstant.RESPONSE_CODE, WxPayJsApiResponseConstant.RESPONSE_SUCCESS_MESSAGE);
            map.put(WxPayJsApiResponseConstant.RESPONSE_MESSAGE, WxPayJsApiResponseConstant.RESPONSE_SUCCESS_MESSAGE);
            logger.info("微信支付回调成功，处理成功 " + map);
        } else {
            response.setStatus(WxPayJsApiResponseConstant.RESPONSE_ERROR);
            map.put(WxPayJsApiResponseConstant.RESPONSE_CODE, WxPayJsApiResponseConstant.RESPONSE_ERROR_MESSAGE);
            map.put(WxPayJsApiResponseConstant.RESPONSE_MESSAGE, "签名错误");
            logger.info("微信支付回调成功，处理失败 " + map);
        }

        // 构建 - 响应信息
        response.setHeader("Content-type", ContentType.JSON.toString());
        response.getOutputStream().write(JSONUtil.toJsonStr(map).getBytes(StandardCharsets.UTF_8));
        response.flushBuffer();

        // 取出微信支付系统生成的订单号。
        String wx_pay_num = (String) JSONUtil.parseObj(plainText).get("transaction_id");
        // 将回调数据转为BO对象
        WxPayJsApiOrderBO order = JSONUtil.toBean(plainText, WxPayJsApiOrderBO.class);
        System.out.println("将回调字符串转为对象："+ order);
        // TODO 根据交易订单号查询openID，构造对象信息存储MySQL中
        PayInfo payInfo = new PayInfo(null, order.getPayer().getOpenid(), wx_pay_num, 0, null, "");
        payInfoService.save(payInfo);
        return wx_pay_num;
    }

    /**
     * 获取微信支付回调通知请求头body内容
     * @param request 获取回调返回的内容
     * @return ·
     */
    public static String getVerifyNotifyBody(HttpServletRequest request) {
        BufferedReader br = null;
        try {
            StringBuilder result = new StringBuilder();
            br = request.getReader();
            for (String line; (line = br.readLine()) != null; ) {
                if (result.length() > 0) {
                    result.append("\n");
                }
                result.append(line);
            }
            return result.toString();
        } catch (IOException e) {
            throw new RuntimeException(e);
        } finally {
            if (br != null) {
                try {
                    br.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    /**
     * v3 支付异步通知验证签名， 解密回调的数据后返回
     * @param body 回调返回内容体
     * @param key API密匙
     */
    public static String verifyNotify(String body, String key) throws Exception {
        // 获取 - 请求body相关加密信息
        JSONObject resultObject = JSONUtil.parseObj(body);
        JSONObject resource = resultObject.getJSONObject(WxPayJsApiNotifyConstant.HTTP_NOTIFY_RESOURCE);
        String cipherText = resource.getStr(WxPayJsApiNotifyConstant.HTTP_NOTIFY_CIPHER_TEXT);
        String nonceStr = resource.getStr(WxPayJsApiNotifyConstant.HTTP_NOTIFY_NONCE);
        String associatedData = resource.getStr(WxPayJsApiNotifyConstant.HTTP_NOTIFY_ASSOCIATED_DATA);

        // 构造 - 解密工具类
        AesUtil aesUtil = new AesUtil(key.getBytes(StandardCharsets.UTF_8));

        // 操作 - 密文解密
        String result = aesUtil.decryptToString(associatedData.getBytes(StandardCharsets.UTF_8), nonceStr.getBytes(StandardCharsets.UTF_8), cipherText);

        return result;
    }
}